﻿using System;
using System.Collections.Generic;
using System.Resources;
using System.Diagnostics;
using System.Globalization;
using Hallenberg.SmartClient.Interfaces;

namespace Hallenberg.SmartClient.Services
{
    class ResourceMapper : IResourceMapper
    {
        private List<ResourceManager> m_ResourceManagers;
        private Dictionary<string, object> m_IndexedResources;
        private Dictionary<string, bool> m_ResourceIndexed;

        public ResourceMapper()
        {
            m_ResourceManagers = new List<ResourceManager>();
            Reset();
        }

        public void Reset()
        {
            m_IndexedResources = new Dictionary<string, object>();
            m_ResourceIndexed = new Dictionary<string, bool>();
        }

        public void RegisterResourceManager(ResourceManager resourceManager)
        {
            Debug.Assert(resourceManager != null);
            if (resourceManager == null)
            {
                throw new ArgumentNullException("resourceManager");
            }

            m_ResourceManagers.Add(resourceManager);
            Reset();
        }

        /// <summary>
        /// Returns the specified resource string.
        /// </summary>
        /// <param name="resourceName">The name of the resource.</param>
        /// <returns>A string if the resource is found.</returns>
        public string GetStringResource(string resourceName, int LCID)
        {
            return GetResource<string>(resourceName, LCID);
        }

        /// <summary>
        /// Iterates through the registered resource managers to find the resource with the 
        /// specified resource name. If the resource has already been looked up a cached version
        /// will be returned.
        /// </summary>
        /// <typeparam name="T">The type of the resource expected.</typeparam>
        /// <param name="resourceName">The name of the resource.</param>
        /// <returns>The found resource of type T or default(T) if not found.</returns>
        /// <exception cref="System.ArgumentNullException">If resourceName is empty or null.</exception>
        private T GetResource<T>(string resourceName, int LCID)
            where T : class
        {
            Debug.Assert(string.IsNullOrEmpty(resourceName) == false);
            if (string.IsNullOrEmpty(resourceName))
            {
                throw new ArgumentNullException("resourceName");
            }

            if (m_ResourceIndexed.ContainsKey(resourceName))
            {
                if (m_ResourceIndexed[resourceName])
                {
                    return m_IndexedResources[resourceName] as T;
                }

                return default(T);
            }

            foreach (ResourceManager resourceManager in m_ResourceManagers)
            {
                T foundValue = resourceManager.GetObject(resourceName, CultureInfo.GetCultureInfo(LCID)) as T;
                if (foundValue != null)
                {
                    m_ResourceIndexed.Add(resourceName, true);
                    m_IndexedResources.Add(resourceName, foundValue);

                    return foundValue;
                }
            }

            return default(T);
        }

        public void ChangeLanguage(string languageCode, LanguageChanged languageChanged)
        {
            Debug.Assert(string.IsNullOrEmpty(languageCode) == false);
            if (string.IsNullOrEmpty(languageCode))
            {
                throw new ArgumentNullException("languageCode");
            }

            Debug.Assert(languageChanged != null);
            if (languageChanged == null)
            {
                throw new ArgumentNullException("languageChanged");
            }

            Reset();

            CultureInfo newCulture = new CultureInfo(languageCode);
            languageChanged(newCulture.LCID);
        }
    }
}
